package com.next

import com.google.gson.Gson
import com.sun.image.codec.jpeg.JPEGCodec
import com.sun.image.codec.jpeg.JPEGImageEncoder
import grails.converters.JSON
import grails.gorm.transactions.Transactional
import groovy.transform.CompileStatic
import groovy.transform.TypeChecked

import javax.imageio.ImageIO
import java.awt.*
import java.awt.image.BufferedImage

import java.security.cert.CertificateException
import java.security.cert.X509Certificate

import javax.net.ssl.HostnameVerifier
import javax.net.ssl.HttpsURLConnection
import javax.net.ssl.SSLContext
import javax.net.ssl.SSLSession
import javax.net.ssl.TrustManager
import javax.net.ssl.X509TrustManager

import com.qiniu.common.QiniuException
import com.qiniu.http.Response
import com.qiniu.storage.UploadManager
import com.qiniu.storage.BucketManager
import com.qiniu.common.Zone
import com.qiniu.storage.Configuration
import com.qiniu.util.Auth
import com.qiniu.util.StringMap

@Transactional
@CompileStatic
@TypeChecked
class FileServerService
{

    static scope = "singleton"

    private static final String BOUNDARY = UUID.randomUUID().toString()
    private static final String PREFIX = "--"
    private static final String LINE_END = "\r\n"
    private static final String CONTENT_TYPE = "multipart/form-data"

    //七牛参数
    String accessKey = "RJXgiiyNZa7xuGNzg0zQbrHWHVdEIM-5yw3XQc0A"
    String secretKey = "bR7o3OWzAozbe8mcgjsZfqR4cKP46VImscPbs76b"
    String bucket = "quickloan"

    //获取七牛上传凭证
    def getUploadToken(String callBackUrl = null)
    {
        println "*****************FileServerService  getUploadToken*******************"
        Auth auth = Auth.create(accessKey, secretKey)
        String upToken
        if (callBackUrl)
        {
            callBackUrl = "https://lms.cindata.cn/" + callBackUrl
            //            callBackUrl = "http://eywj37.natappfree.cc/" + callBackUrl
            StringMap putPolicy = new StringMap()
            putPolicy.put("callbackUrl", callBackUrl)
            putPolicy.put("callbackBody", "{opportunityId:\$(x:opportunityId),type:\$(x:type),description:\$(x:description),fileName:\$(key)}")
            putPolicy.put("callbackBodyType", "application/json")
            long expireSeconds = 3600
            upToken = auth.uploadToken(bucket, null, expireSeconds, putPolicy)
        }
        else
        {
            upToken = auth.uploadToken(bucket)
        }

        upToken
    }

    //app获取七牛上传凭证
    def appGetUploadToken(String callBackUrl = null)
    {
        println "*****************FileServerService  appGetUploadToken*******************"
        Auth auth = Auth.create(accessKey, secretKey)
        String upToken
        if (callBackUrl)
        {
            callBackUrl = "https://lms.cindata.cn/" + callBackUrl
            //            callBackUrl = "http://eywj37.natappfree.cc/" + callBackUrl
            StringMap putPolicy = new StringMap()
            putPolicy.put("callbackUrl", callBackUrl)
            putPolicy.put("callbackBody", "{opportunitySerialNumber:\$(x:opportunitySerialNumber),appSessionId:\$(x:appSessionId),attachmentType:\$(x:attachmentType),fileType:\$(x:fileType),description:\$(x:description),fileName:\$(key)}")
            putPolicy.put("callbackBodyType", "application/json")
            long expireSeconds = 3600
            upToken = auth.uploadToken(bucket, null, expireSeconds, putPolicy)
        }
        else
        {
            upToken = auth.uploadToken(bucket)
        }

        upToken
    }

    //助手端获取七牛上传凭证
    def appUploadGetUploadToken(String callBackUrl = null)
    {
        println "*****************FileServerService  appUploadGetUploadToken*******************"
        Auth auth = Auth.create(accessKey, secretKey)
        String upToken
        if (callBackUrl)
        {
            //            callBackUrl = "http://l206m58959.51mypc.cn:17664/" + callBackUrl
            callBackUrl = "https://lms.cindata.cn/" + callBackUrl
            StringMap putPolicy = new StringMap()
            putPolicy.put("callbackUrl", callBackUrl)
            putPolicy.put("callbackBody", "{opportunityId:\$(x:opportunityId),activityId:\$(x:activityId),displayOrder:\$(x:displayOrder),appSessionId:\$(x:appSessionId),attachmentType:\$(x:attachmentType),fileType:\$(x:fileType),description:\$(x:description),fileName:\$(key)}")
            putPolicy.put("callbackBodyType", "application/json")
            long expireSeconds = 3600
            upToken = auth.uploadToken(bucket, null, expireSeconds, putPolicy)
        }
        else
        {
            upToken = auth.uploadToken(bucket)
        }

        upToken
    }

    //删除七牛上的文件
    def remove3(String fileName)
    {
        println "delete from qiniu"
        Configuration cfg = new Configuration(Zone.zone1())
        String accessKey = "RJXgiiyNZa7xuGNzg0zQbrHWHVdEIM-5yw3XQc0A"
        String secretKey = "bR7o3OWzAozbe8mcgjsZfqR4cKP46VImscPbs76b"
        String bucket = "quickloan"
        def result = true

        Auth auth = Auth.create(accessKey, secretKey)
        BucketManager bucketManager = new BucketManager(auth, cfg)
        try
        {
            def key = fileName.substring(fileName.lastIndexOf("/") + 1)
            bucketManager.delete(bucket, key)
        }
        catch (QiniuException ex)
        {
            result = false
            println "delete from qiniu exceptionCode:" + ex.code()
            println "delete from qiniu exceptionMessage:" + ex.response.toString()
        }
        return result
    }

    //上传至七牛服务器
    def upload3(File file, String fileType)
    {
        println "wx upload to qiniu"
        Configuration cfg = new Configuration(Zone.zone1())
        UploadManager uploadManager = new UploadManager(cfg)

        def fileName = ""
        def code = UUID.randomUUID().toString()
        String key = code + "." + fileType
        String upToken = getUploadToken()
        try
        {
            Response response = uploadManager.put(file, key, upToken)
            def responseMessage = JSON.parse(response.bodyString())
            fileName = responseMessage['key']
            println "fileName:" + fileName

        }
        catch (QiniuException ex)
        {
            Response r = ex.response
            println "QiniuException:" + r.toString()
            try
            {
                println "Qiniu exception body:" + r.bodyString()
            }
            catch (QiniuException ex2)
            {
                println "QiniuException2:" + ex2
            }
        }
        return fileName
    }

    def upload(String avatar, String fileType)
    {
        URL url = new URL("https://10.10.21.10:8443/attachment/upload")
        String code = "bc6f36e9-9e28-4c67-874f-e77748978d20"
        def params = "file=" + URLEncoder.encode(avatar, "UTF-8") + "&fileType=" + URLEncoder.encode(fileType, "UTF-8") + "&code=" + URLEncoder.encode(code, "UTF-8")
        HttpURLConnection connection = (HttpURLConnection) url.openConnection()
        connection.setDoOutput(true)
        connection.setRequestMethod("POST")
        connection.outputStream.withWriter { Writer writer -> writer.write params }

        def externalId = ""
        def response = connection.inputStream.withReader { Reader reader -> reader.text }
        if (response)
        {
            externalId = JSON.parse(response).getAt("externalId")
        }
        println "fileName: " + externalId
        return externalId
    }

    def upload1(File file, Map<String, String> param)
    {
        println "==================upload1 files=============================="

        String result = ""
        HttpURLConnection conn = null
        DataOutputStream dos = null
        try
        {
            // 设置请求头信息
            URL url = new URL("https://10.10.21.10:8443/attachment/upload")
            // URL url = new URL("https://quickloanfs.cindata.cn/attachment/upload")
            // 忽略HTTPS请求的SSL证书，必须在openConnection之前调用
            ignoreSsl()

            conn = (HttpURLConnection) url.openConnection()
            conn.setReadTimeout(60000)
            conn.setConnectTimeout(60000)
            conn.setDoInput(true)
            conn.setDoOutput(true)
            conn.setUseCaches(false)
            conn.setRequestMethod("POST")
            conn.setRequestProperty("Charset", "utf-8")
            conn.setRequestProperty("connection", "keep-alive")
            conn.setRequestProperty("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1)")
            conn.setRequestProperty("Content-Type", CONTENT_TYPE + ";boundary=" + BOUNDARY)

            dos = new DataOutputStream(conn.getOutputStream())

            // 参数上传
            if (param != null && param.size() > 0)
            {
                Iterator<String> it = param.keySet().iterator()
                while (it.hasNext())
                {
                    String key = it.next()
                    String value = param.get(key)

                    StringBuffer sb = new StringBuffer()
                    sb.append(PREFIX).append(BOUNDARY).append(LINE_END)
                    sb.append("Content-Disposition: form-data; name=\"").append(key).append("\"").append(LINE_END).append(LINE_END)
                    sb.append(value).append(LINE_END)
                    dos.write(sb.toString().getBytes())
                }
            }

            // 文件上传
            StringBuffer sb = new StringBuffer()
            sb.append(PREFIX).append(BOUNDARY).append(LINE_END)
            sb.append("Content-Disposition:form-data; name=\"file\"; filename=\"" + file.getName() + "\"" + LINE_END)
            sb.append("Content-Type:image/pjpeg" + LINE_END)
            sb.append(LINE_END)
            dos.write(sb.toString().getBytes())
            InputStream is = new FileInputStream(file)
            byte[] bytes = new byte[is.available()]
            int len = 0
            while ((len = is.read(bytes)) != -1)
            {
                dos.write(bytes, 0, len)
            }
            is.close()
            dos.write(LINE_END.getBytes())
            byte[] end_data = (PREFIX + BOUNDARY + PREFIX + LINE_END).getBytes()
            dos.write(end_data)
            dos.flush()
            dos.close()

            // 返回值处理
            if (conn.getResponseCode() == 200)
            {
                def response = conn.inputStream.withReader { Reader reader -> reader.text }
                if (response)
                {
                    def responseMessage = JSON.parse(response)
                    if (responseMessage.getAt("errorCode"))
                    {
                        println "文件上传失败：" + responseMessage.getAt("errorMessage")
                    }
                    else
                    {
                        result = responseMessage.getAt("externalId")
                        println "fileName: " + result + "." + param['fileType']
                    }
                }
            }
            else
            {
                println "文件上传失败，错误码：" + conn.getResponseCode()
            }
        }
        catch (Exception e)
        {
            println "File upload failure reason: "
            println e
        }

        return result
    }

    def remove(String file)
    {
        String fileName = file.split('\\.')[0]
        String fileType = file.split('\\.')[-1]
        println "删除的文件名：${fileName}.${fileType}"

        URL url = new URL("http://s27.cindata.com/fs/attachment/remove")
        String code = "bc6f36e9-9e28-4c67-874f-e77748978d20"
        def params = "fileName=" + URLEncoder.encode(fileName, "UTF-8") + "&fileType=" + URLEncoder.encode(fileType,
                                                                                                           "UTF-8") + "&code=" + URLEncoder.encode(code, "UTF-8")
        HttpURLConnection connection = (HttpURLConnection) url.openConnection()
        connection.setDoOutput(true)
        connection.setRequestMethod("POST")
        connection.outputStream.withWriter { Writer writer -> writer.write params }

        def response = connection.inputStream.withReader { Reader reader -> reader.text }
    }

    def compress(String fileName, Integer w, Integer h)
    {
        try
        {
            File file = new File(fileName)
            Image img = ImageIO.read(file)
            Integer width = img.getWidth(null)
            Integer height = img.getHeight(null)

            if (width / height > w / h)
            {
                h = (Integer) (height * w / width)
            }
            else
            {
                w = (Integer) (width * h / height)
            }

            BufferedImage image = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB)
            image.getGraphics().drawImage(img.getScaledInstance(w, h, Image.SCALE_SMOOTH), 0, 0, null)
            // image.getGraphics().drawImage(img.getScaledInstance(w, h,  Image.SCALE_AREA_AVERAGING), 0, 0, null)

            File destFile = new File(fileName)
            FileOutputStream out = new FileOutputStream(destFile)

            JPEGImageEncoder encoder = JPEGCodec.createJPEGEncoder(out)
            encoder.encode(image)

            return fileName
        }
        catch (Exception e)
        {
            println e.message
            return ""
        }
    }

    def compress1(File file, Map<String, String> param)
    {
        try
        {
            Integer w = 100
            Integer h = 100
            Image img = ImageIO.read(file)
            Integer width = img.getWidth(null)
            Integer height = img.getHeight(null)

            if (width / height > w / h)
            {
                h = (Integer) (height * w / width)
            }
            else
            {
                w = (Integer) (width * h / height)
            }

            BufferedImage image = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB)
            image.getGraphics().drawImage(img.getScaledInstance(w, h, Image.SCALE_SMOOTH), 0, 0, null)
            // image.getGraphics().drawImage(img.getScaledInstance(w, h,  Image.SCALE_AREA_AVERAGING), 0, 0, null)
            // ImageIO.write(image, "JPEG", new File(distImgPath));

            // File destFile = file
            FileOutputStream out = new FileOutputStream(file)
            JPEGImageEncoder encoder = JPEGCodec.createJPEGEncoder(out)
            encoder.encode(image)
            out.close()
            def fileName = upload1(file, param)
            return fileName
        }
        catch (Exception e)
        {
            println e.message
            return ""
        }
    }

    private static void trustAllHttpsCertificates() throws Exception
    {
        TrustManager[] trustAllCerts = new TrustManager[1]
        TrustManager tm = new miTM()
        trustAllCerts[0] = tm
        SSLContext sc = SSLContext.getInstance("SSL")
        sc.init(null, trustAllCerts, null)
        HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory())
    }

    static class miTM implements TrustManager, X509TrustManager
    {
        X509Certificate[] getAcceptedIssuers()
        {
            return null
        }

        boolean isServerTrusted(X509Certificate[] certs)
        {
            return true
        }

        boolean isClientTrusted(X509Certificate[] certs)
        {
            return true
        }

        void checkServerTrusted(X509Certificate[] certs, String authType) throws CertificateException
        {
            return
        }

        void checkClientTrusted(X509Certificate[] certs, String authType) throws CertificateException
        {
            return
        }
    }

    /**
     * 忽略HTTPS请求的SSL证书，必须在openConnection之前调用
     * @throws Exception
     */
    static void ignoreSsl() throws Exception
    {
        HostnameVerifier hv = new HostnameVerifier() {
            boolean verify(String urlHostName, SSLSession session)
            {
                return true
            }
        }
        trustAllHttpsCertificates()
        HttpsURLConnection.setDefaultHostnameVerifier(hv)
    }

    /**
     * 精准估值获取七牛凭证，回调函数修改opportunityId为contactId，新添加参数城市id
     * @author fc* @date 2018-04-11 10：16:55
     */
    def getUploadTokenPrecise(String callBackUrl = null)
    {
        Auth auth = Auth.create(accessKey, secretKey)
        String upToken
        if (callBackUrl)
        {
            callBackUrl = "https://lms.cindata.cn/" + callBackUrl
            StringMap putPolicy = new StringMap()
            putPolicy.put("callbackUrl", callBackUrl)
            putPolicy.put("callbackBody", "{contactId:\$(x:contactId),type:\$(x:type),description:\$(x:description),fileName:\$(key),city:\$(x:city)}")
            putPolicy.put("callbackBodyType", "application/json")
            long expireSeconds = 3600
            upToken = auth.uploadToken(bucket, null, expireSeconds, putPolicy)
        }
        else
        {
            upToken = auth.uploadToken(bucket)
        }

        upToken
    }

    /**
     * 意见反馈获取七牛凭证，回调函数修参数修改
     * @author fc* @date 2018-04-11 10：16:55
     */
    def getUploadTokenSuggest(String callBackUrl = null)
    {
        Auth auth = Auth.create(accessKey, secretKey)
        String upToken
        if (callBackUrl)
        {
            callBackUrl = "https://lms.cindata.cn/" + callBackUrl
            StringMap putPolicy = new StringMap()
            putPolicy.put("callbackUrl", callBackUrl)
            putPolicy.put("callbackBody", "{type:\$(x:type),description:\$(x:description),fileName:\$(key)}")
            putPolicy.put("callbackBodyType", "application/json")
            long expireSeconds = 3600
            upToken = auth.uploadToken(bucket, null, expireSeconds, putPolicy)
        }
        else
        {
            upToken = auth.uploadToken(bucket)
        }

        upToken
    }

}
